package cn.kbyue.security.security;

import cn.kbyue.security.entity.KbPermission;
import cn.kbyue.security.entity.RolePermissions;
import cn.kbyue.security.service.RolePermissionService;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;

/**
 * 读取可访问 URL 的角色信息，
 *
 * @author xl
 * @date 2020/4/19 16:10
 */
@Slf4j
@Component
public class CustomFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    @Resource
    private RolePermissionService rolePermissionService;

    /**
     * 从配置的权限表、角色-权限表中 确定访问 url 需要的角色 code
     * 其它未在 角色权限表 中作关联的 url 可匿名访问
     *
     * @see cn.kbyue.security.security.CustomAccessDecisionManager 执行校验
     * @param object url
     * @throws IllegalArgumentException 非法参数异常
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        // 获取当前请求url
        final String ignoreLoginUrl = "/login";
        final String ignoreLogoutUrl = "logout";
        final String requestUrl = ((FilterInvocation) object).getRequestUrl();
        if (ignoreLoginUrl.equals(requestUrl) || requestUrl.contains(ignoreLogoutUrl)) {
            return null;
        }

        List<RolePermissions> allRolePermission = rolePermissionService.getAllRolePermission();
        String[] roles = allRolePermission.stream()
                .filter(rolePermissions -> {
                    List<KbPermission> permission = rolePermissions.getPermission();
                    return permission.stream().anyMatch(kbPermission -> kbPermission.getUrl().contains(requestUrl));
                })
                .map(rolePermissions -> rolePermissions.getRole().getCode())
                .toArray(String[]::new);

        log.info(">> 访问Url: {} 的角色: {}", requestUrl, Arrays.asList(roles));

        return SecurityConfig.createList(roles);
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
}
